//*************************************************************************************************
//************************ (C) 2001 - 2006, Eleven Engineering Incorporated ***********************
//*************************************************************************************************
//**
//**		Tabs:	This file looks best with tab stops set every 6 spaces.
//**
//*************************************************************************************************
//*************************************************************************************************
//**
//**          File:  XPD Echo.asm
//**       Project:  XInc2 Library
//**       Created:  04 Jan 2003 by Ryan Northcott
//**       Revised:  08 Sep 2006 by Dan Beutel
//**
//**   Description:  Firmware subroutines to echo ASCII messges to a terminal program connected to
//**                 the XInc2 Program / Debug Port.  To use these routines in your project, you
//**                 must include the file "XPD_Echo_Data.asm" in your "LongData.asm" file.
//**
//** Compatibility:  Requires XInA v4.4 or higher.
//**
//**    Disclaimer:  You may incorporate this sample source code into your program(s) without
//**                 restriction.  This sample source code has been provided "AS IS" and the
//**                 responsibility for its operation is yours.  You are not permitted to
//**                 redistribute this sample source code as "Eleven sample source code" after
//**                 having made changes.  If you are going to re-distribute the source, we require
//**                 that you make it clear in the source that the code was descended from Eleven
//**                 sample source code, but that you have made changes.
//**
//*************************************************************************************************
//*************************************************************************************************
//**
//**	XPD_EchoString
//**	XPD_EchoUnsignedDec
//**	XPD_EchoUnsignedDecNLZ
//**	XPD_EchoSignedDec
//**	XPD_EchoSignedDecNLZ
//**	XPD_EchoHex
//**	XPD_EchoHexNP
//**	XPD_EchoHexByte
//**	XPD_EchoHexByteNP
//**	XPD_EchoSetBitList
//**	XPD_EchoBlock
//**
//*************************************************************************************************
//*************************************************************************************************

#ifndef __XPD_ECHO__
#define __XPD_ECHO__

#include "Math.asm"
#include "XPD Serial.asm"

//=============================================================================
// Input Params:	r1 = Pointer to a Null Terminated String
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Used to echo ASCII Strings to a computer terminal for
//              debugging.  Newlines and other control characters can be
//              embedded in the string.  All strings must be
//              Null-terminated with the End-Of-String character (EOS).
//=============================================================================
XPD_EchoString:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3

		add	r2, r1, 0				// Copy r1 to r2
	XPD_EchoString_loop1:
		ld	r1, r2, 0				// Read in character
		bc	CC, XPD_EchoString_END
		jsr	r6, XPD_WriteByte
		add	r2, r2, 1
		bra	XPD_EchoString_loop1

XPD_EchoString_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Unsigned Integer
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit unsigned integer to the terminal.  Leading
//              zeros are output if necessary to pad the output to 5 digits.
//=============================================================================
XPD_EchoUnsignedDec:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3

		// Determine 10000's digit
		mov	r2, 10000
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 1000's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 1000
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 100's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 100
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 10's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 10
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 1's digit
		add	r1, r2, 0				// Remainder = 1's digit
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result
		
XPD_EchoUnsignedDec_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Unsigned Integer
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit unsigned integer to the terminal without leading
//              zeros (No Leading Zeros).
//=============================================================================
XPD_EchoUnsignedDecNLZ:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3

		// Determine 10000's digit
		mov	r2, 10000
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoUnsignedDecNLZ_1000
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoUnsignedDecNLZ_1000:
		// Determine 1000's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 1000
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoUnsignedDecNLZ_100
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoUnsignedDecNLZ_100:
		// Determine 100's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 100
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoUnsignedDecNLZ_10
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoUnsignedDecNLZ_10:
		// Determine 10's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 10
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoUnsignedDecNLZ_1
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoUnsignedDecNLZ_1:
		// Determine 1's digit
		add	r1, r2, 0				// Copy remainder to r1 (1's digit)
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result
		
XPD_EchoUnsignedDecNLZ_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Signed Integer
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit signed integer to the terminal.  Leading
//              zeros are output if necessary to pad the output to 5 digits.
//              In total, 6 characters are output: 1 sign and 5 digits.
//=============================================================================
XPD_EchoSignedDec:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3
		
		// Determine the sign character
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDec_Zero
		bc	NC, XPD_EchoSignedDec_Positive
	
	XPD_EchoSignedDec_Negative:
		mov	r1, '-'
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer
		mov	r2, 0
		sub	r1, r2, r1				// Convert to positive representation
		bra	XPD_EchoSignedDec_Digits
	
	XPD_EchoSignedDec_Positive:
		mov	r1, '+'
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer
		bra	XPD_EchoSignedDec_Digits
		
	XPD_EchoSignedDec_Zero:
		mov	r1, ' '
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer

	XPD_EchoSignedDec_Digits:

		// Determine 10000's digit
		mov	r2, 10000
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 1000's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 1000
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 100's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 100
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 10's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 10
		jsr	r6, UnsignedDivide
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

		// Determine 1's digit
		add	r1, r2, 0				// Remainder = 1's digit
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result
		
XPD_EchoSignedDec_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Signed Integer
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit signed integer to the terminal without leading
//              zeros (No Leading Zeros).
//=============================================================================
XPD_EchoSignedDecNLZ:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3
		
		// Determine the sign character
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDecNLZ_Zero
		bc	NC, XPD_EchoSignedDecNLZ_Positive
	
	XPD_EchoSignedDecNLZ_Negative:
		mov	r1, '-'
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer
		mov	r2, 0
		sub	r1, r2, r1				// Convert to positive representation
		bra	XPD_EchoSignedDecNLZ_Digits
	
	XPD_EchoSignedDecNLZ_Positive:
		mov	r1, '+'
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer
		bra	XPD_EchoSignedDecNLZ_Digits
		
	XPD_EchoSignedDecNLZ_Zero:
		mov	r1, ' '
		jsr	r6, XPD_WriteByte
		ld	r1, sp, -3				// Reload the integer

	XPD_EchoSignedDecNLZ_Digits:

		// Determine 10000's digit
		mov	r2, 10000
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDecNLZ_1000
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoSignedDecNLZ_1000:
		// Determine 1000's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 1000
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDecNLZ_100
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoSignedDecNLZ_100:
		// Determine 100's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 100
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDecNLZ_10
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoSignedDecNLZ_10:
		// Determine 10's digit
		add	r1, r2, 0				// Copy remainder to r1
		mov	r2, 10
		jsr	r6, UnsignedDivide
		add	r1, r1, 0
		bc	ZS, XPD_EchoSignedDecNLZ_1
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result

	XPD_EchoSignedDecNLZ_1:
		// Determine 1's digit
		add	r1, r2, 0				// Copy remainder to r1 (1's digit)
		add	r1, r1, '0'
		jsr	r6, XPD_WriteByte			// Echo result
		
XPD_EchoSignedDecNLZ_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Number
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit number to the terminal formatted as a
//              hexadecimal integer with format 0xABCD where ABCD are hex
//              digits.
//=============================================================================
XPD_EchoHex:
		st	r1, sp, 0
		st	r6, sp, 1
		add	sp, sp, 2

		mov	r1, MSG_HEX_PREFIX
		jsr	r6, XPD_EchoString		// Echo leading "0x"
		
		ld	r1, sp, -2
		jsr	r6, XPD_EchoHexNP
		
XPD_EchoHex_END:
		sub	sp, sp, 2
		ld	r1, sp, 0
		ld	r6, sp, 1
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-bit Number
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos a 16-bit number to the terminal formatted as a
//              hexadecimal integer without the '0x' prefix (No prefix).
//=============================================================================
XPD_EchoHexNP:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3

		add	r2, r1, 0				// Copy r1 to r2

		rol	r1, r2, 4
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert MSD
		jsr	r6, XPD_WriteByte			// Echo to stdout

		rol	r1, r2, 8
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert next digit
		jsr	r6, XPD_WriteByte			// Echo to stdout

		rol	r1, r2, 12
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert next digit
		jsr	r6, XPD_WriteByte			// Echo to stdout

		rol	r1, r2, 0
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert LSD
		jsr	r6, XPD_WriteByte			// Echo to stdout
		
XPD_EchoHexNP_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 8-bit Number
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos an 8-bit number to the terminal formatted as a
//              hexadecimal integer with the '0x' prefix.
//=============================================================================
XPD_EchoHexByte:
		st	r1, sp, 0
		st	r6, sp, 1
		add	sp, sp, 2

		mov	r1, MSG_HEX_PREFIX
		jsr	r6, XPD_EchoString		// Echo leading "0x"
		
		ld	r1, sp, -2
		jsr	r6, XPD_EchoHexByteNP
		
XPD_EchoHexByte_END:
		sub	sp, sp, 2
		ld	r1, sp, 0
		ld	r6, sp, 1
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 8-bit Number
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos an 8-bit number to the terminal formatted as a
//			hexadecimal integer without the '0x' prefix (No Prefix).
//=============================================================================
XPD_EchoHexByteNP:
		st	r1, sp, 0
		st	r2, sp, 1
		st	r6, sp, 2
		add	sp, sp, 3

		add	r2, r1, 0				// Copy r1 to r2

		rol	r1, r2, 12
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert MSD
		jsr	r6, XPD_WriteByte			// Echo to stdout

		rol	r1, r2, 0
		and	r1, r1, 0x000F
		ld	r1, r1, table_bintohex		// Convert LSD
		jsr	r6, XPD_WriteByte			// Echo to stdout
		
XPD_EchoHexByteNP_END:
		sub	sp, sp, 3
		ld	r1, sp, 0
		ld	r2, sp, 1
		ld	r6, sp, 2
		jsr	r6, r6


//=============================================================================
// Input Params:	r1 = 16-Bit Vector
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos to the terminal a comma deliminated list of the bits
//			that are set in a 16-bit vector.
//=============================================================================
XPD_EchoSetBitList:
		st	r0, sp, 0
		st	r1, sp, 1
		st	r2, sp, 2
		st	r3, sp, 3
		st	r4, sp, 4
		st	r5, sp, 5
		st	r6, sp, 6
		add	sp, sp, 7
		
		mov	r2, 0					// Previous Bit = FALSE
		mov	r3, 15
		mov	r4, 0					// i = 0
		add	r0, r1, 0				// r0 = r1
		
	XPD_EchoSetBitList_loop:
		sub	r1, r3, r4
		rol	r1, r0, r1				// Test Bit i
		bc	NC, XPD_EchoSetBitList_loop_end
		
		add	r2, r2, 0				// Test For Previous Bit
		bc	ZS, XPD_EchoSetBitList_output
		
		mov	r1, MSG_COMMA			// Output ", "
		jsr	r6, XPD_EchoString

	XPD_EchoSetBitList_output:
		mov	r2, 1					// Previous Bit = TRUE
		add	r1, r4, 0				// Output i
		jsr	r6, XPD_EchoUnsignedDecNLZ

	XPD_EchoSetBitList_loop_end:
		add	r4, r4, 1				// i++
		sub	r5, r4, 16
		bc	ZC, XPD_EchoSetBitList_loop
		
XPD_EchoSetBitList_END:
		sub	sp, sp, 7
		ld	r0, sp, 0
		ld	r1, sp, 1
		ld	r2, sp, 2
		ld	r3, sp, 3
		ld	r4, sp, 4
		ld	r5, sp, 5
		ld	r6, sp, 6
		jsr	r6, r6
	

//=============================================================================
// Input Params:	r4 = Number of words to display
//			r5 = Start address of the block
// Output Params:	None
//-----------------------------------------------------------------------------
// Description:	Echos to the terminal a given number of words of data in
//			hex format starting at a given memory address.  The output is
//			formatted with 8 words per line and a space inbetween each
//			word.
//=============================================================================
XPD_EchoBlock:
		st	r0, sp, 0
		st	r1, sp, 1
		st	r2, sp, 2
		st	r3, sp, 3
		st	r4, sp, 4
		st	r5, sp, 5
		st	r6, sp, 6
		add	sp, sp, 7
		
		add	r4, r4, 0
		bc	ZS, XPD_EchoBlock_END
		
	XPD_EchoBlock_lineLoop:
		mov	r3, 8					// r3 = words on this line
	XPD_EchoBlock_wordLoop:
		ld	r1, r5, 0
		jsr	r6, XPD_EchoHex
		mov	r1, ' '
		jsr	r6, XPD_WriteByte
		add	r5, r5, 1				// Increment address
		sub	r4, r4, 1				// Decrement total
		bc	ZS, XPD_EchoBlock_END
		sub	r3, r3, 1				// Decrement words on this line
		bc	ZC, XPD_EchoBlock_wordLoop
		mov	r1, MSG_NEWLINE			// Start new line
		jsr	r6, XPD_EchoString
		bra	XPD_EchoBlock_lineLoop

XPD_EchoBlock_END:
		sub	sp, sp, 7
		ld	r0, sp, 0
		ld	r1, sp, 1
		ld	r2, sp, 2
		ld	r3, sp, 3
		ld	r4, sp, 4
		ld	r5, sp, 5
		ld	r6, sp, 6
		jsr	r6, r6
		
#endif